#include "sandlight.h"
#include "ui_sandlight.h"

sandLight::sandLight(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::sandLight)
{
    ui->setupUi(this);
    setUI(this);
    this->setWindowTitle(PluginName);
    pD=new picDialog*[PpicNum];
    range=new rflRange[PpicNum];
    for(int i=0;i<PpicNum;i++){
        pD[i]=nullptr;
    }
    Btn.push_back(ui->LoadPic_Btn);
}

sandLight::~sandLight()
{
    delete ui;
    if(pD!=nullptr){
        for(int i=0;i<PpicNum;i++){
            if(pD[i]!=nullptr){
                delete pD[i],pD[i]=nullptr;
            }
        }
        delete[] pD;
        pD=nullptr;
    }
    if(range!=nullptr){
        delete[] range,range=nullptr;
    }
}

void sandLight::on_workBtn_clicked()
{
    QString fileName;
    fileName=QFileDialog::getSaveFileName(this,tr("Save As"),"",tr("*.png"));

    if(!fileName.isEmpty()){
        //---------先判断文件是否已经存在---------
        QFileInfo fi(fileName);
        bool T=writeSand(fileName);
        if(!T){
            QMessageBox::critical(this,"错误提示","文件写入失败!");
            return;
        }

    }
    else
        return;
}

bool sandLight::writeSand(QString& QfileName) {
    std::string fileName = QfileName.toUtf8().constData();
    int W = ui->recWidth->value()*1000/ui->processReso->value();
    int H = ui->recHeight->value()*1000/ui->processReso->value();

    //-----------------创建一个进度条-------------
    QProgressDialog *progress = new QProgressDialog(
        "正在生成数据", "取消生成", 0, 0, this);
    progress->setWindowTitle("请等待");
    progress->setWindowModality(Qt::WindowModal);
    makeT = true;
    connect(progress, &QProgressDialog::canceled, this, [=]() mutable {
        makeT = false;
    });

    // 添加进度更新的信号连接
    connect(this, &sandLight::updateProgress, progress, &QProgressDialog::setValue);

    progress->show();

    // 启动后台线程进行处理
    m_writeFuture = QtConcurrent::run([=]() -> bool {
        std::string errMsg;
        PngWriter writer;
        if (!writer.init(fileName, W, H, errMsg)) {
            return false;
        }

        constexpr int CHUNK_ROWS = 1000;
        int writeCount = 0;
        BYTE** picA = allocate2DArray(CHUNK_ROWS, W);
        BYTE** picB = allocate2DArray(CHUNK_ROWS, W);

        // ... 其他初始化代码 ...
        long sideH = H, sideW = W;
        std::vector<point> pSet;
        double PyDist = ui->sandSize->value()/ui->processReso->value()/2;
        randomP_sort(sideW, sideH, PyDist, pSet);

        int cpuNum = 20;
        ZERO_ThreadPool threadpool;
        threadpool.init(cpuNum);
        threadpool.start();
        long writeNum = int(pSet.size() / cpuNum);
        BYTE*** pic = new BYTE * *[cpuNum];
        pic_Info* pLB = new pic_Info[cpuNum];
        double RndSize = 0.1*ui->sandSize->value();
        range[sandAngel] = {ui->beginAngel->value()/180*M_PI+M_PI/2, ui->endAngel->value()/180*M_PI+M_PI/2};

        // 使用信号更新最大值
        emit updateProgress(0); // 先设为0
        QMetaObject::invokeMethod(progress, "setMaximum",
                                  Qt::QueuedConnection,
                                  Q_ARG(int, writeNum));

        for (long i = 0; i < writeNum; i++) {
            Pyramid** PY = new Pyramid * [cpuNum];
            if(makeT) {
                // ... 原有的处理逻辑 ...
                for (int j = 0; j < cpuNum; j++) {
                    long sitePicW = pSet[i * cpuNum + j].x/(ui->picReso->value()/ui->processReso->value());
                    long sitePicH = pSet[i * cpuNum + j].y/(ui->picReso->value()/ui->processReso->value());
                    double Height = 1.1*ui->sandSize->value()+(0.5-rand() / double(RAND_MAX))*RndSize;
                    double Width = 0.9*ui->sandSize->value()+(0.5-rand() / double(RAND_MAX))*RndSize;
                    double angel = range[sandAngel].minNum + rand() / double(RAND_MAX) * (range[sandAngel].maxNum-range[sandAngel].minNum);
                    if(pD[sandAngel] != nullptr)
                        pD[sandAngel]->reflectWay(sitePicW, sitePicH, sandAngel, angel, range);
                    angel = angel+(0.5-rand() / double(RAND_MAX))*PI/12;
                    PY[j] = new Pyramid(pSet[i * cpuNum + j], Height, Width, angel);
                }

                class std::future<unsigned char* __ptr64* __ptr64>* pF = new class std::future<unsigned char* __ptr64* __ptr64>[cpuNum];
                for (int j = 0; j < cpuNum; j++) {
                    pF[j] = threadpool.exec(std::bind(&Pyramid::make_pyramid, PY[j], std::placeholders::_1), ref(pLB[j]));
                }

                threadpool.waitForAllDone();

                for (int j = 0; j < cpuNum; j++) {
                    pic[j] = pF[j].get();
                    for (int m = 0; m < pLB[j].H; m++) {
                        for (int n = 0; n < pLB[j].W; n++) {
                            long iRow = m + int(pLB[j].pLB.y) - writeCount*CHUNK_ROWS;
                            long iCol = n + int(pLB[j].pLB.x);
                            int Gray = pic[j][m][n];

                            if (iRow < CHUNK_ROWS && iRow >= 0 && iCol >= 0 && iCol < W) {
                                if (picA[iRow][iCol] < Gray) picA[iRow][iCol] = Gray;
                            }
                            else if (iRow - CHUNK_ROWS < CHUNK_ROWS && iRow - CHUNK_ROWS >= 0 && iCol >= 0 && iCol < W) {
                                if (picB[iRow - CHUNK_ROWS][iCol] < Gray) picB[iRow - CHUNK_ROWS][iCol] = Gray;
                            }
                        }
                    }
                    delete PY[j];
                    PY[j] = nullptr;
                }

                delete[] pF; pF = nullptr;
                delete[] PY; PY = nullptr;

                // 使用信号发送进度更新，而不是直接调用
                // 删除：progress->setValue(i);
                emit updateProgress(i);
            }

            if (pSet[i * cpuNum].y - writeCount * CHUNK_ROWS > 1.5 * CHUNK_ROWS) {
                writer.writeRows(picA, CHUNK_ROWS);
                writeCount++;
                for (long j = 0; j < CHUNK_ROWS; j++) {
                    memcpy(picA[j], picB[j], W);
                    memset(picB[j], 0, W);
                }
            }

            if (!makeT) {
                break;
            }
        }
        // 在写入所有行后，更新进度条状态为保存中
        QMetaObject::invokeMethod(progress, "setLabelText",
                                  Qt::QueuedConnection,
                                  Q_ARG(QString, "正在保存PNG文件..."));
        // 重置进度条，设置新的范围
        QMetaObject::invokeMethod(progress, "setMaximum",
                                  Qt::QueuedConnection,
                                  Q_ARG(int, 100));
        QMetaObject::invokeMethod(progress, "setValue",
                                  Qt::QueuedConnection,
                                  Q_ARG(int, 0));
        // 最后一次写入
        writer.writeRows(picA, CHUNK_ROWS);
        // 更新进度到30%
        QMetaObject::invokeMethod(progress, "setValue",
                                  Qt::QueuedConnection,
                                  Q_ARG(int, 10));
        // 使用带进度回调的finalize方法
        writer.finalize(errMsg, [&](int percent) {
            // 将30%-100%映射到进度条的30%-100%
            int mappedPercent = 10 + (percent * 90 / 100);
            QMetaObject::invokeMethod(progress, "setValue",
                                      Qt::QueuedConnection,
                                      Q_ARG(int, mappedPercent));
        });

        // 释放资源
        free2DArray(picA, CHUNK_ROWS);
        free2DArray(picB, CHUNK_ROWS);

        // 设置进度条完成
        //emit updateProgress(writeNum);

        return makeT;
    });

    // 设置完成处理函数
    QFutureWatcher<bool>* watcher = new QFutureWatcher<bool>(this);
    connect(watcher, &QFutureWatcher<bool>::finished, this, [=]() {
        bool result = m_writeFuture.result();
        if (result) {
            QMessageBox::information(this, tr("砂效制作"), "Finished!");
        } else {
            if (QFile::exists(QfileName)) {
                QFile::remove(QfileName);
            }
        }
        progress->deleteLater();
        watcher->deleteLater();
    });
    watcher->setFuture(m_writeFuture);

    return true;
}

void sandLight::on_LoadPic_Btn_clicked()
{
    QString str="砂映射";
    long suitPicw=ui->recWidth->value()*1000/ui->picReso->value();
    long suitPich=ui->recHeight->value()*1000/ui->picReso->value();
    picDialog::ctrlPicBtn(sandAngel,cnt,pD,str,suitPicw,suitPich,this);
}

